#pragma once

#include<mutex>
#include<iostream>

template<class T>
class UniquePtr
{
    UniquePtr<T>& operator=(const UniquePtr<T>&) = delete;
    UniquePtr(const UniquePtr<T>&) = delete;
public:
    UniquePtr(T* ptr)
        :_ptr(ptr)
    {}
    ~UniquePtr()
    {
        if(_ptr)
            delete _ptr;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};
///////////////////第一版失败的设计
// template<class T>
// class SharedPtr
// {
// public:
//     SharedPtr(T* ptr)
//         :_ptr(ptr)
//         ,_usecount(1)
//     {}
//     SharedPtr<T>& operator=(const SharedPtr<T>& obj)
//     {
//         _ptr = obj._ptr;
//         _usecount = obj._usecount
//     }
//     ~SharedPtr()
//     {
//         --_usecount;
//         if(_usecount == 0)
//         {
//             if(_ptr)
//                 delete _ptr;
//         }
//     }
// private:
//     T* _ptr;
//     size_t _usecount;
//     //如果设置在栈上，那么每一个对象都有一个独立的引用计数
//     //每一次自增自减都需要对同一引用计数的所有对象维护，非常难以维护
// };


template<class T>
class SharedPtr
{
public:
    SharedPtr(T* ptr)
        :_ptr(ptr)
        ,_refcount(new int{1})
        ,_pmtx(new std::mutex)
    {}

    SharedPtr(const SharedPtr<T>& obj)
        :_ptr(obj._ptr)//浅拷贝
        ,_refcount(obj._refcount)
        ,_pmtx(obj._pmtx)
    {
        AddRef();
    }

    SharedPtr<T>& operator=(const SharedPtr<T>& obj)
    {
        if(obj._ptr != _ptr)//不能给自身赋值
        {
            Release();//释放掉被赋值的智能指针对象的原有资源
            //浅拷贝
            _ptr = obj._ptr;//两个指针指向同一个T*对象
            _refcount = obj._refcount;//两个指针指向同一个int*
            _pmtx = obj._pmtx;//两个指针指向同一个mutex*的锁
            AddRef();
        }
    }
    void AddRef()
    {//增加引用计数需要加锁
        _pmtx->lock();
        (*_refcount)++;
        _pmtx->unlock();
    }

    void Release()
    {
        _pmtx->lock();
        bool f = false;
        if(--(*_refcount) == 0 && _ptr)
        {
            f = true;
            delete _ptr;
            delete _refcount;
        }
        _pmtx->unlock();
        if(f == true)
        {
            delete _pmtx;
        }
    }
    ~SharedPtr()
    {
        Release();
    }
    int UseCount()
    {
        return *_refcount;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    T* GetPtr()
    {
        return _ptr;
    }
private:
    T* _ptr;
    int* _refcount;
    std::mutex* _pmtx;//考虑线程安全
    //如果设置在栈上，那么每一个对象都有一个独立的引用计数
    //每一次自增自减都需要对同一引用计数的所有对象维护，非常难以维护
};

// 简化版本的weak_ptr实现
template<class T>
class WeakPtr
{
public:
    WeakPtr()
        :_ptr(nullptr)
    {}

    WeakPtr(const SharedPtr<T>& sp)
        :_ptr(sp.get())
    {}

    WeakPtr<T>& operator=(const SharedPtr<T>& sp)
    {
        _ptr = sp.get();
        return *this;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};

